package data;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.TreeMap;

import entities.ScheduleActivity;
import entities.ScheduleDay;


public class ScheduleActivityPlacer {

	public ScheduleActivityPlacer() {

	}

	/**
	 * @Author Simon
	 * 
	 * Mutator algorithm that (hopefully) assigns a unique timeslot to all the activities in a
	 * input list. It's probably ordo n^millions, but it's the best I can do for now.
	 * 
	 * @param scheduleList - list to be sorted.
	 * @throws Exception
	 */
	public void scheduleFixer(ArrayList<ScheduleActivity> scheduleList)
			throws Exception {
		System.out.println("Jag startades!");
		TreeMap<Integer, ArrayList<ScheduleActivity>> sortingMap = new TreeMap<Integer, ArrayList<ScheduleActivity>>();

		// Creates a map where each 15 minute interval gets assigned a list of
		// Activities that occupies that time.
		// Will also set the TimeShares to the default, in case it has been
		// altered elsewhere
		for (ScheduleActivity sa : scheduleList) {
			sa.setTimeShare(1);
			sa.setTimeSharePos(0);
			for (int i = sa.getStartTime(); i <= sa.getEndTime(); i += 15) {
				if (sortingMap.containsKey(i)) {
					sortingMap.get(i).add(sa);
				} else {
					ArrayList<ScheduleActivity> tmp = new ArrayList<ScheduleActivity>();
					tmp.add(sa);
					sortingMap.put(i, tmp);
				}

				if (i % 100 == 45) {
					i = i - 45 + 85;
				}
			}

		}

		for (ScheduleActivity sa : scheduleList) {
			int maxCollisions = 0;
			int collisionAt = 0;
			int tempSize;
			// Goes through the Activities and sees where the first maximum
			// collision occur
			for (int i = sa.getStartTime(); i <= sa.getEndTime(); i += 15) {

				tempSize = sortingMap.get(i).size();
				if ((tempSize > 1) && (tempSize > (maxCollisions + 1))) {
					maxCollisions = tempSize - 1;
					collisionAt = i;
				}

				if (i % 100 == 45) {
					i = i - 45 + 85;
				}
			}

			// If no collisions have been found, then the default values will
			// do.
			if (maxCollisions > 0) {
				ArrayList<ScheduleActivity> collisions = sortingMap
						.get(collisionAt);
				ScheduleActivity[] slotList = new ScheduleActivity[collisions
						.size()];
				for (ScheduleActivity collAct : collisions) {

					// Basically: if TimeShare is larger than 1 this SA has been
					// processed before, and already have a slot.
					if (collAct.getTimeShare() > 1) {
						if (collAct.getTimeShare() < maxCollisions) {
							collAct.setTimeShare(maxCollisions + 1);
						}
						int entitledSlot = collAct.getTimeSharePos() - 1;
						// If there's something here already, it (should) mean that 
						// an unentitled SA have been put in that timeslot and should be moved.
						if (slotList[entitledSlot] != null) {
							ScheduleActivity relocatedAct = slotList[entitledSlot];
							slotList[entitledSlot] = collAct;
							boolean foundNoPos = true;
							for (int i = 0; i < collisions.size(); i++) {
								if (slotList[i] == null) {
									slotList[i] = relocatedAct;
									collAct.setTimeSharePos(i + 1);
									foundNoPos = false;
									break;
								}
							}
							if (foundNoPos) {
								throw new Exception();
								// This should not be possible, I really hope it will never happen.
							}

						} else {

							slotList[entitledSlot] = collAct;

						}

					}
					// If TimeShare wasn't larger than 1, then a timeslot must
					// be assigned. This timeslot will logically be "unentitled" untill the slotList is filled.
					else {
						collAct.setTimeShare(maxCollisions + 1);
						boolean foundNoPos = true;
						for (int i = 0; i < collisions.size(); i++) {
							if (slotList[i] == null) {
								slotList[i] = collAct;
								collAct.setTimeSharePos(i + 1);
								foundNoPos = false;
								break;
							}
						}
						if (foundNoPos) {
							throw new Exception();
							// This should not be possible, I really hope it will never happen.
						}

					}

				}

			}

		}
	}
	
	/**
	 * 
	 * @Author Simon
	 * 
	 * Quicker check if there are any collisions at all. Will of course add extra time if
	 * there are collisions but decrease the time when there are none. 
	 * @param scheduleList - list to check for collisions in
	 * @return True if there are collisions, else false.
	 */
	public boolean isTimeCollision(ArrayList<ScheduleActivity> scheduleList) {
		HashSet<Integer> collisionSet = new HashSet<Integer>();
		boolean collisionCheck;
		for (ScheduleActivity sa : scheduleList) {
			for (int i = sa.getStartTime(); i <= sa.getEndTime(); i += 15) {
				collisionCheck = collisionSet.add(i);
				if (!collisionCheck) {
					return true;
				}
				if (i % 100 == 45) {
					i = i - 45 + 85;
				}
			}

		}
		return false;

	}

}

